﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Windows.Forms;
using DemoEF.Model;

namespace DemoEF
{
    public partial class ConcurrencyManagement : Form
    {
        public ConcurrencyManagement()
        {
            InitializeComponent();
        }

        private void txtProductId_TextChanged(object sender, EventArgs e)
        {
            try
            {
                using (var Db = new ProductDbContext())
                {
                    txtpProductName.Text = Db.Products.Find(Int32.Parse(txtProductId.Text)).Name;
                }

            }
            catch (Exception ex)
            {

            }
        }

        private void btnFirstWin_Click(object sender, EventArgs e)
        {
            using (var db = new ProductDbContext())
            {
                var productId = int.Parse(txtProductId.Text);

                var product = db.Products.Find(productId);

                // Change value directly in the DB
                using (var contextDb = new ProductDbContext())
                {
                    contextDb.Database.ExecuteSqlCommand(
                        "UPDATE Products SET Name_Editted = 'FirstWins' WHERE ProductId = {0}", productId);
                }

                //Change memory value
                product.Name = "NewName" + Guid.NewGuid();

                //Display
                lblDbvalue.Text = "Database Value: " + db.Entry(product).GetDatabaseValues().GetValue<string>("Name");
                lblOriginalValue.Text = "Original value: " + db.Entry(product).Property(s => s.Name).OriginalValue;
                lblCurrentValue.Text = "Current value: " + db.Entry(product).Property(s => s.Name).CurrentValue;

                try
                {
                    lblLog.Text = "New name is saved";
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    // Not possible to perform change because of differences between original and DB value                   
                    var ctx = ((IObjectContextAdapter)db).ObjectContext;
                    ctx.Refresh(RefreshMode.StoreWins, product);
                    lblLog.Text = "Have conflict, use FirstWin";
                }


                //Get final value
                lblFinalValue.Text = "Final value: " + product.Name;
            }
        }

        private void btnLastWin_Click(object sender, EventArgs e)
        {
            using (var db = new ProductDbContext())
            {
                var productId = int.Parse(txtProductId.Text);
                bool savedChanges = false;
                var product = db.Products.Find(productId);

                // Change value directly in the DB
                using (var contextDb = new ProductDbContext())
                {
                    contextDb.Database.ExecuteSqlCommand(
                        "UPDATE Products SET Name_Editted = 'LastWins' WHERE ProductId = {0}", productId);
                }

                product.Name = "NewName" + Guid.NewGuid();

                //Display
                lblDbvalue.Text = "Database Value: " + db.Entry(product).GetDatabaseValues().GetValue<string>("Name");
                lblOriginalValue.Text = "Original value: " + db.Entry(product).Property(s => s.Name).OriginalValue;
                lblCurrentValue.Text = "Current value: " + db.Entry(product).Property(s => s.Name).CurrentValue;

                while (!savedChanges)
                {
                    try
                    {
                        db.SaveChanges();
                        savedChanges = true;

                        lblLog.Text += " New name is saved";
                    }
                    catch (DbUpdateConcurrencyException ex)
                    {
                        // Update original value with DB value
                        //var entry = ex.Entries.FirstOrDefault();
                        //if (entry != null) entry.OriginalValues.SetValues(entry.GetDatabaseValues());

                        var ctx = ((IObjectContextAdapter)db).ObjectContext;
                        ctx.Refresh(RefreshMode.ClientWins, product);

                        lblLog.Text = "Have conflict, use LastWin!";
                    }
                }


                //Get final value
                var productFinal = db.Products.Find(productId);
                lblFinalValue.Text = "Final value: " + productFinal.Name;
            }
        }

        //Demo Transaction in EF
        private void btnBeginTransaction_Click(object sender, EventArgs e)
        {
            using (var db = new ProductDbContext())
            {
                using (var scope = new TransactionScope())
                {
                    
                    try
                    {
                        //Do transacs here
                        db.Products.Add(new Product() { Name = "Transaction", CategoryId = 1});
                        db.Products.Add(new Product() { Name = "Transaction2", CategoryId = 2 });
                        db.SaveChanges();

                        //Complete when every transacs is sucessful.
                        scope.Complete();
                        lblLog.Text = "Transaction complete";
                    }
                    catch (Exception ex)
                    {
                        lblLog.Text = ex.Message;
                    }

                }
                
            }




        }

    }
}
